home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 134_01.zip / CORO2.CSM < prev    next >
Text File  |  1993-06-12  |  8KB  |  347 lines

  1. ;    CORO2.CSM
  2.  
  3. ;    Copyright (c) 1983 by Kevin B. Kenny
  4. ;    Released to the BDS `C' Users' Group for non-commercial distribution
  5.  
  6. ;    Kevin Kenny
  7. ;    729-A E. Cochise Dr.
  8. ;    Phoenix, Arizona   85020
  9.  
  10. ;    Assembly language auxiliary functions for coroutine management
  11.  
  12. ;        This file comprises assembly language definitions of
  13. ;    auxiliary functions needed by the BDS C coroutine manager. The
  14. ;    following are included:
  15.  
  16. ;    sbrk        Version of sbrk that accounts for the existence of
  17. ;            multiple stacks.
  18. ;    corstart    Procedure that gets a coroutine started for the
  19. ;            first time, and handles the "falloff" condition.
  20. ;    corpass        Procedure that does the "dirty work" of passing
  21. ;            control from one coroutine to another.  
  22. ;    corwmip        Static storage for coroutine linkages.
  23. ;            Procedure to handle trying to detach main.
  24.  
  25.     maclib "BDS"
  26.  
  27.     FUNCTION    sbrk; (size)    size in bytes
  28.     EXTERNAL    corwmip
  29.  
  30.     call    ma1toh        ; Pick up the size to allocate
  31.     push    b
  32.     push    h
  33.  
  34.     call    corwmip        ; Call WMIP to get current FCV.  If
  35.     mov    e,m        ; it's the main coroutine, then it's
  36.     inx    h        ; located at WMIP+2, and the current
  37.     mov    d,m        ; stack pointer is the correct one.
  38.     inx    h        ; Otherwise, the stack bounds check
  39.     mov    a,h        ; needs to use the stack pointer of
  40.     cmp    d        ; the main coroutine.
  41.     jnz    nmain
  42.     mov    a,l
  43.     cmp    e
  44.     jz    main
  45.  
  46. nmain:    mov    a,m        ; We're in a subsidiary coroutine; get
  47.     inx    h        ; The stack pointer of main from 0-1 in
  48.     mov    h,m        ; it's FCV.
  49.     mov    l,a
  50.     jmp    tests
  51.  
  52. main:    lxi    h,0        ; We're in main coroutine; get the stack
  53.     dad    sp        ; pointer.
  54.  
  55. tests:    pop    d        ; Set DE=size to allocate;
  56.     push    h        ; TOS=stack pointer
  57.  
  58.     lhld    allocp        ; Get the heap pointer, and add the
  59.     dad    d        ; request size.  If it carries out,
  60.     jc    error        ; request will not fit in memory.
  61.  
  62.     dcx    h        ; Set DE=stack pointer, TOS=new top of
  63.     pop    d        ; heap (avail + size - 1).
  64.     push    h        
  65.  
  66.     lhld    alocmx        ; Get HL=stack pointer-alocmx; this is
  67.     call    cmh        ; the maximum value for the new heap
  68.     dad    d        ; pointer.
  69.     
  70.     pop    d        ; Compare the new heap pointer with the
  71.     mov    a,h        ; computed maximum value.
  72.     cmp    d
  73.     jnz    comp2
  74.     mov    a,l
  75.     cmp    e
  76. comp2:    jc    error2        ; It's higher -- oops!
  77.  
  78.     lhld    allocp        ; Get heap pointer -> piece to return
  79.     xchg            ; Update heap pointer
  80.     inx    h
  81.     shld    allocp
  82.  
  83.     xchg
  84.     pop    b
  85.     ret
  86.  
  87. error:    pop    h        ; Request exceeds memory size; clean up stk.
  88. error2:    lxi    h,0        ; Excessive request-- return 0 for denial.
  89.     pop    b        ; Recover saved frame base pointer
  90.     ret
  91.  
  92.     ENDFUNC    sbrk
  93.  
  94.  
  95.  
  96.     FUNCTION    corstart
  97.     EXTERNAL    corpass, corwmip
  98.  
  99. ;        This function is the coroutine starter.  It is invoked
  100. ;    the first time control is passed to a created coroutine.  BC
  101. ;    will be the address of the function to call (the "main program"
  102. ;    of the coroutine) and HL will be the initial argument.  We save
  103. ;    the initial entry on the stack, in case the function "falls off
  104. ;    the end", and then call the initial entry passing the passed arg.
  105.  
  106. begin:    push    b        ; Save initial entry
  107.     push    h        ; Prepare the argument
  108.     mov    h,b        ; Get entrypoint in HL
  109.     mov    l,c
  110.     call    dopchl        ; Call the function
  111.  
  112. ;        The called coroutine has fallen off the end.  We need to
  113. ;    fake the DETACH, and then (after reinvocation) restart it.
  114.  
  115.     pop    b        ; Retrieve function pointer, after
  116.     pop    b        ; discarding prepared argument.  Stack is
  117.                 ; now empty.
  118.  
  119.     push    h        ; Save return value on stack; it will
  120.                 ; be used as 2nd arg to corpass.
  121.  
  122.     call    corwmip        ; Get the pointer to our fcv.
  123.     mov    a,m
  124.     inx    h
  125.     mov    h,m
  126.     mov    l,a
  127.  
  128.     lxi    d,4        ; Get pointer to caller's fcv
  129.     dad    d
  130.     mov    a,m
  131.     inx    h
  132.     mov    h,m
  133.     mov    l,a
  134.  
  135.     push    h        ; Prepare caller fcv as 1st arg to pass$.
  136.  
  137.     lxi    d,6        ; Now get pointer to caller's "type" word.
  138.     dad    d    
  139.  
  140.     mvi    m,4        ; Set pass type to "return"
  141.     inx    h
  142.     mvi    m,0
  143.  
  144.     call    corpass; (caller, return$val)
  145.  
  146. ;        We have been reinvoked.  BC is still the initial entry 
  147. ;    point, and HL is the passed value.  Throw away the arguments that
  148. ;    we passed to corpass, and restart the coroutine.
  149.  
  150.     pop    d
  151.     pop    d
  152.     jmp    begin
  153.  
  154. ;        The following instruction is used to call the initial
  155. ;    entry via HL.
  156.  
  157. dopchl:    pchl
  158.  
  159.     ENDFUNC    corstart
  160.  
  161.  
  162.  
  163.     FUNCTION    corpass ;(fcv, passval)
  164.     EXTERNAL    corwmip
  165.  
  166. ;        This function does all the "dirty work" needed to get
  167. ;    from one coroutine to another.  It maintains the "who-am-I" and
  168. ;    "passer" linkages, saves register content from one invocation to
  169. ;    the next, and does the reloading of the stack pointer and the
  170. ;    transfer of control.
  171.  
  172. ;    First, save the BC register of the departing coroutine:
  173.  
  174.     push    b
  175.  
  176. ;    Get a pointer to the memory location in which the WMI pointer
  177. ;    resides (BC) and to the current FCV (DE).
  178.  
  179.     call    corwmip
  180.     mov    b,h    
  181.     mov    c,l
  182.     mov    e,m
  183.     inx    h
  184.     mov    d,m
  185.  
  186. ;    Save the current stack pointer at Cf$stkptr$ in the current FCV.
  187. ;    The stack looks like:
  188. ;        +0    BC register storage
  189. ;        +2    Return address
  190. ;        +4    Target FCV
  191. ;        +6    Passed value
  192.  
  193.     lxi    h,0
  194.     dad    sp
  195.     xchg
  196.     mov    m,e
  197.     inx    h
  198.     mov    m,d
  199.     dcx    h
  200.     xchg        ; FCV pointer back in DE.
  201.  
  202. ;    Get a pointer to target coroutine in HL
  203.  
  204.     lxi    h,4
  205.     dad    sp
  206.     mov    a,m
  207.     inx    h
  208.     mov    h,m
  209.     mov    l,a
  210.  
  211. ;    Set the "passer" word in the target to designate the source.
  212.  
  213.     inx    h        ; Passer is at relative location 2
  214.     inx    h
  215.     mov    m,e
  216.     inx    h
  217.     mov    m,d
  218.     dcx    h
  219.     dcx    h
  220.     dcx    h
  221.  
  222. ;    Set the WMI linkage to the target coroutine:
  223.  
  224.     mov    a,l
  225.     stax    b        ; WMI is still in BC
  226.     inx    b
  227.     mov    a,h
  228.     stax    b
  229.     xchg            ; Target FCV now in DE.
  230.  
  231. ;    Get the passed value:
  232.  
  233.     lxi    h,6
  234.     dad    sp
  235.     mov    a,m
  236.     inx    h
  237.     mov    h,m
  238.     mov    l,a
  239.     xchg            ; DE = passed value; HL=target FCV
  240.  
  241. ;    Reload the stack pointer from the target FCV
  242.  
  243.     mov    a,m
  244.     inx    h
  245.     mov    h,m
  246.     mov    l,a
  247.     sphl
  248.  
  249. ;    Put the passed arg in HL, restore the BC register, and go back
  250. ;    to the target coroutine's saved return address.
  251.  
  252.     xchg
  253.     pop    b
  254.     ret
  255.  
  256.     ENDFUNC    corpass
  257.  
  258.  
  259.  
  260.     FUNCTION    corwmip
  261.     EXTERNAL    fprintf, exit
  262.  
  263. ;        This function contains the static storage used by the
  264. ;    coroutine package.  It also has the code that handles the case
  265. ;    where the main coroutine (or one which has been RESUMEd by it)
  266. ;    has tried to DETACH.
  267.  
  268. ;    When we're called, return pointer to the word inmemory where
  269. ;    the WMI linkage is stored:
  270.  
  271.     lxi    h,wmiptr
  272.     ret
  273.  
  274. ;    First static area is the WMI linkage:
  275.  
  276. wmiptr:    dw    mainfcv        ; Initially, main coroutine running.
  277.  
  278. ;    Then comes the main coroutine's FCV:
  279. ;    *** SBRK depends on this following WMIP; don't change it...
  280.  
  281. mainfcv:
  282.     ds    2    ; Space for stack pointer
  283.     dw    falloff    ; Passer -- dumy "falloff" FCV
  284.     dw    falloff ; Caller
  285.     dw    0    ; Type is unknown.
  286.     dw    -8    ; Stack size is ridiculous.
  287.     dw    0    ; User info is zero.
  288.  
  289. ;     Next is a dummy FCV for the "falloff" condition:
  290.  
  291. falloff:
  292.     dw    fallstk    ; Stack pointer
  293.     dw    falloff    ; Linked to self as caller
  294. passer:    dw    falloff ; Linked to self as passer
  295.     dw    0    ; Type is unknown
  296.     dw    16    ; 6 bytes of stack space
  297.     dw    0    ; User info word is 0
  298.  
  299. ;    The "falloff" coroutine's stack follows:    
  300.  
  301.     ds    12    ; Space for interrupt handler, JIC...
  302. fallstk: dw    0    ; BC register save is unused.
  303.     dw    mainend    ; Return address is "main end" procedure
  304.  
  305. ;         The following code handles the problems
  306. ;    that arise when the main co-routine tries to return.  It
  307. ;    calls fprintf to display an error message, then exits.  It
  308. ;    can be modified by removing the call to exit() so that it
  309. ;    will continue the "main" coroutine instead.
  310.  
  311. mainend:
  312.     lhld    passer        ; Who fouled up?
  313.     shld    wmiptr        ; Whoever it was, re-enter it.
  314.  
  315.     mov    a,m        ; Restore the stack pointer of the
  316.     inx    h        ; coroutine that fell off.
  317.     mov    h,m
  318.     mov    l,a
  319.     sphl
  320.  
  321.     lhld    passer        ; Prepare passer ptr as 3rd arg to abort
  322.     push    h
  323.  
  324.     lxi    h,message    ; Prepare error message pointer as 2nd arg
  325.     push    h
  326.  
  327.     lxi    h, 4        ; Prepare unit 4 (STDERR) as the 1st arg
  328.  
  329.     call    fprintf ;(STD_ERR, message, passer)
  330.  
  331.     pop    b
  332.     pop    b    ; Discard args
  333.     pop    b
  334.  
  335.     call    exit        ; Quit
  336.  
  337.     pop    b    ;Get BC back
  338.     ret            ; Resume the turkey
  339.  
  340. message:
  341.     db    0AH, 'Attempt to detach a coroutine (FCV=0x%04x) which has'
  342.     db    0AH, 'no caller linkage.'
  343.     db    0
  344.  
  345.     ENDFUNC    corwmip
  346. ed.
  347.     dw    mainend    ;